package netcom;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import codeoffloading.CodeOffloadingManager;
import utilities.SerializableClassUtility;
import netcom.exceptions.ServerUnreachable;
import netcom.messages.ExecutionReplyMessage;
import netcom.messages.ExecutionRequestMessage;
import netcom.messages.Message;

public class ServerThread implements Runnable {

	private Socket sock;

	private ServiceInstance inst;
	private int connectionId;

	private boolean run = true;

	public ServerThread(int connectionid, ServiceInstance _inst){
		// open socket
		inst = _inst;
		this.connectionId = connectionid;
		
	}
	
	
	public void instantiatedSocket() throws ServerUnreachable{
		try {
			sock = new Socket(inst.getServIp(), inst.getServPort());
		} catch (UnknownHostException e) {
			throw new ServerUnreachable();
		} catch (IOException e) {
			throw new ServerUnreachable();
		}
	}

	public void sendServerMessage(ExecutionRequestMessage mex)
			throws ServerUnreachable {
		
		
		this.instantiatedSocket();
		
		if (!sock.isConnected())
			throw new ServerUnreachable();

		OutputStream out;
		try {
			out = sock.getOutputStream();

			byte[] b = utilities.SerializableClassUtility
					.getBytesFromClass(mex);
			DataOutputStream dos = new DataOutputStream(out);
			int len = b.length;
			dos.writeInt(len);
			if (len > 0) {
				dos.write(b, 0, len);
			}

			dos.close();
			//wakeup listen thread
			this.notifyAll();
		} catch (IOException e) {
			throw new ServerUnreachable();
		}
		// sock.close();
	}

	
	public void run() {
		while(run){
			
			try {
				this.wait();
			} catch (InterruptedException e1) { e1.printStackTrace();}
			
			DataInputStream in;
			try {
				in = new DataInputStream(sock.getInputStream());
			
			int len = in.readInt();
			byte[] message = new byte[len]; 
			in.readFully(message);
			if(len > 0){
					Message off = (netcom.messages.Message)SerializableClassUtility.getMessaFromBytes(message);
					if(off instanceof ExecutionReplyMessage){
					CodeOffloadingManager.getInstance().methodResults((ExecutionReplyMessage)off);
					NetManager.getInstance().removeConnection(connectionId);
					}else{
						System.err.print("Message error > wrong class received");
					}
			}else{
				System.err.print("Message error length < 0");
			}
			sock.close();
			} catch (IOException e) {
				System.err.println(e.toString());
			}
			
		}
	}

}
